package com.xcity.tools.template;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import naga.x.util.IOUtils;
import naga.x.util.StringUtils;

/**
 * 模板类生成器
 * @author yang.li
 *
 */
public class TemplateClassCreater {

	//!!!-----need manual modify-----!!!
	/** 配置文件路径 */
	public static final File XLS = new File("F:/prj_java_svn/gd/01-配置表/group_buy.xlsx");
	/** 表格索引（若为-1，则按表格名查找） */
	public static int SHEET = 1;
	/** 表格名（表格索引为-1时生效） */
	public static String SHEET_NAME = "在线竞技段位";
	/** 模板类类名 */
	public static final String CLASS = "com.xcity.game.activity2.groupbuy.template.GroupBuyScoreRewardTemplate";
//	public static final String CLASS = "com.xcity.tools.http.template.MenuOpenTemplate";
	/** 类文件（*.java）存放目录 */
	public static final File CLASS_DIR = new File("F:/prj_java_svn/city-server/src/main/java");
//	public static final File CLASS_DIR = new File("F:/prj_java_svn/city-tools/src/main/java");
	/** 该模板类创建者（@author） */
	public static final String AUTHOR = "yang.li";
	//!!!-----need manual modify-----!!!
	
	public static int sheetIndex;
	public static String sheetName;
	
	public static class Head {
		public String name;
		public String type = "int"; // default
		public String desc;
		@Override
		public boolean equals(Object obj) {
			if (obj instanceof Head) {
				Head h = (Head) obj;
				return h.name.equals(name);
			}
			return false;
		}
		String getGetterName() {
			char prefix = Character.toUpperCase(name.charAt(0));
			if (name.length() == 1) {
				return ("boolean".equals(type) ? "is" : "get") + prefix;
			}
			return ("boolean".equals(type) ? "is" : "get") + prefix + name.substring(1, name.length());
		}
		String getSetterName() {
			char prefix = Character.toUpperCase(name.charAt(0));
			if (name.length() == 1) {
				return "set" + prefix;
			}
			return "set" + prefix + name.substring(1, name.length());
		}
	}
	
	public static void main(String[] args) throws Exception {
		long t = System.currentTimeMillis();
		Workbook book = getWorkbook(XLS);
		List<Head> headList = mergeHead(readHead(book));
		createJava(headList);
		System.out.println("ok." + (System.currentTimeMillis() - t) + " millis.\n" + getJavaFile().getAbsolutePath());
	}
	
	public static Workbook getWorkbook(File xls) throws Exception {
		if (xls.getName().endsWith("xlsx")) {
			return new XSSFWorkbook(xls);
		}
		return new HSSFWorkbook(new FileInputStream(xls));
	}
	
	public static List<Head> readHead(Workbook book) throws Exception {
		List<Head> list = new ArrayList<Head>();
		Sheet sheet = SHEET != -1 ? book.getSheetAt(SHEET) : book.getSheet(SHEET_NAME);
		sheetIndex = book.getSheetIndex(sheet);
		sheetName = sheet.getSheetName();
		for (int i = 0; i < 3; i++) {
			Row row = sheet.getRow(i);
			int from = row.getFirstCellNum();
			int to = row.getLastCellNum();
			for (int j = from; j < to; j++) {
				Cell cell = row.getCell(j);
				if (cell == null/* || StringUtils.isEmpty(val = cell.getStringCellValue().trim())*/) {
					break;
				}
				String val = StringUtils.trim(cell.getStringCellValue());
				Head head;
				if (j >= list.size()) {
					head = new Head();
					list.add(head);
				} else {
					head = list.get(j);
				}
				switch (i) {
					case 0: // name
						head.name = val;
						break;
					case 1: // type
						head.type = filterFieldType(val);
						break;
					case 2: // desc
						head.desc = val;
						break;
				}
			}
		}
		return list;
	}
	
	static String[] filedTypes = {
			"byte", "boolean", "char", "short", "int", "long", "float", "double", "String",
			"byte[]", "boolean[]", "char[]", "short[]", "int[]", "long[]", "float[]", "double[]", "String[]",
	};
	static String filterFieldType(String type) {
		type = StringUtils.trim(type);
		if (StringUtils.isEmpty(type)) {
			return "int"; // default
		}
		for (String filedType : filedTypes) {
			if (filedType.equalsIgnoreCase(type)) {
				return filedType;
			}
		}
		return hasChinese(type) ? "int" : type; // default
	}
	
	static boolean hasChinese(String s) {
		return Pattern.compile("[\u4e00-\u9fa5]").matcher(s).find();
	}
	
	static List<Head> mergeHead(List<Head> src) {
		if (src == null || src.isEmpty()) {
			return src;
		}
		List<Head> list = new ArrayList<Head>();
		for (Head h : src) {
			if (StringUtils.isNotEmpty(h.name) && !"id".equals(h.name) && !list.contains(h)) {
				list.add(h);
			}
		}
		return list;
	}
	
	static void createJava(List<Head> headList) throws Exception {
		File java = getJavaFile();
		if (!java.exists()) {
			File parent = java.getParentFile();
			if (parent != null && !parent.exists()) {
				parent.mkdirs();
			}
			java.createNewFile();
		}
		BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(java), IOUtils.UTF8));
		writePackage(writer);
		writeImports(writer);
		writeClassComment(writer);
		writeClassBegin(writer);
		writeFields(writer, headList);
		writeGetterSetter(writer, headList);
		writeClassEnd(writer);
		writer.flush();
		writer.close();
	}
	
	static File getJavaFile() {
		String java = CLASS.replace('.', '/');
		return new File(CLASS_DIR, java + ".java");
	}
	
	static String getJavaPackage() {
		int dot = CLASS.lastIndexOf('.');
		if (dot < 0) {
			return null;
		}
		return CLASS.substring(0, dot);
	}
	
	static String getJavaClassName() {
		int dot = CLASS.lastIndexOf('.');
		if (dot < 0) {
			return CLASS;
		}
		return CLASS.substring(dot + 1);
	}
	
	static void writePackage(BufferedWriter writer) throws Exception {
		String pkg = getJavaPackage();
		if (StringUtils.isEmpty(pkg)) {
			return;
		}
		writer.append("package ").append(pkg).append(";");
		writer.newLine();
		writer.newLine();
	}
	
	static void writeImports(BufferedWriter writer) throws Exception {
		writer.write("import naga.x.game.template.Template;");
		writer.newLine();
		writer.write("import naga.x.game.template.TemplateException;");
		writer.newLine();
		writer.write("import naga.x.game.template.annotation.Binding;");
		writer.newLine();
		writer.append("import naga.x.game.template.annotation.Excel;");
		writer.newLine();
		writer.newLine();
	}
	
	static void writeClassComment(BufferedWriter writer) throws Exception {
		if (StringUtils.isEmpty(sheetName)) {
			return;
		}
		writer.append("/**");
		writer.newLine();
		writer.append(" * ").append(sheetName);
		writer.newLine();
		writer.append(" * @author ").append(AUTHOR);
		writer.newLine();
		writer.write(" *");
		writer.newLine();
		writer.write(" */");
		writer.newLine();
	}
	
	static void writeClassBegin(BufferedWriter writer) throws Exception {
		String s = SHEET != -1 ? "sheet" : "sheetName";
		Object s2 = SHEET != -1 ? sheetIndex : '"' + sheetName + '"';
		writer.write("@Excel(value = \"" + XLS.getName() + "\", " + s + " = " + s2 + ")");
		writer.newLine();
		writer.append("public class ").append(getJavaClassName()).append(" extends Template {");
		writer.newLine();
		writer.newLine();
	}
	
	static void writeClassEnd(BufferedWriter writer) throws Exception {
		writer.newLine();
		writer.write("\t@Override");
		writer.newLine();
		writer.write("\tpublic void validate() throws TemplateException {}");
		writer.newLine();
		writer.write("}");
		writer.newLine();
	}

	static void writeFields(BufferedWriter writer, List<Head> headList) throws Exception {
		for (Head head : headList) {
			writer.append("\t/** ").append(head.desc).append(" */");
			writer.newLine();
			writer.append("\tprotected ").append(head.type).append(" ").append(head.name).append(";");
			writer.newLine();
			writer.newLine();
		}
	}
	
	static void writeGetterSetter(BufferedWriter writer, List<Head> headList) throws Exception {
		for (Head head : headList) {
			// getter
			writer.append("\tpublic ").append(head.type).append(" ").append(head.getGetterName()).append("() {");
			writer.newLine();
			writer.append("\t\treturn ").append(head.name).append(";");
			writer.newLine();
			writer.append("\t}");
			writer.newLine();
			writer.newLine();
			
			// setter
			writer.append("\tpublic void ").append(head.getSetterName()).append("(" + head.type + " " + head.name + ") {");
			writer.newLine();
			writer.append("\t\tthis.").append(head.name).append(" = ").append(head.name).append(";");
			writer.newLine();
			writer.append("\t}");
			writer.newLine();
			writer.newLine();
		}
	}
	
	
	
}
